#include "stdafx.h"
#include "Application.h"
#include "FakeFramework.h"

#include "FakeD3D10Blob.h"
#include "FakeD3D11ComputeShader.h"
#include "FakeD3D11DepthStencilView.h"
#include "FakeD3D11Device.h"
#include "FakeD3D11DeviceContext.h"
#include "FakeD3D11RenderTargetView.h"

#include "DXUT.h"

using namespace MandelShader;

struct ApplicationFixture
{
	ApplicationFixture()
		: framework(),
		app(CreateApplication(&framework))
	{
	}

	FakeFramework framework;
	std::auto_ptr<IApplication> app;
};

#define APPLICATION_TEST_CASE(name_) BOOST_FIXTURE_TEST_CASE(name_, ApplicationFixture)

APPLICATION_TEST_CASE(Construct)
{
	BOOST_REQUIRE(app.get() != 0);
}

APPLICATION_TEST_CASE(IsDeviceAcceptableNoComputeShader)
{
	CD3D11EnumDeviceInfo info;
	info.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x = FALSE;
	BOOST_REQUIRE(!app->IsDeviceAcceptable(0, 0, &info, DXGI_FORMAT_UNKNOWN, false));
}

APPLICATION_TEST_CASE(IsDeviceAcceptableHasComputeShader)
{
	CD3D11EnumDeviceInfo info;
	info.ComputeShaders_Plus_RawAndStructuredBuffers_Via_Shader_4_x = TRUE;
	BOOST_REQUIRE(app->IsDeviceAcceptable(0, 0, &info, DXGI_FORMAT_UNKNOWN, false));
}

APPLICATION_TEST_CASE(ModifyDeviceSettings)
{
	BOOST_REQUIRE(app->ModifyDeviceSettings(0));
}

APPLICATION_TEST_CASE(OnCreateDeviceShaderCreated)
{
	framework.FindMediaFakeResult = _T("c:\\tmp\\ComputeShader.hlsl");
	FakeD3D10Blob byteCode;
	framework.CompileFromFileFakeResult = &byteCode;
	framework.CompileFromFileFakeHResult = S_OK;
	framework.CompileFromFileFakeErrors = 0;
	FakeD3D11Device device;
	FakeD3D11ComputeShader shader;
	device.CreateComputeShaderFakeResult = &shader;
	device.CreateComputeShaderFakeHResult = S_OK;
	BOOST_REQUIRE(SUCCEEDED(app->OnCreateDevice(&device, 0)));
	BOOST_REQUIRE(framework.FindMediaCalled);
	BOOST_REQUIRE(_T("ComputeShader.hlsl") == framework.FindMediaLastFileName);
	BOOST_REQUIRE(framework.CompileFromFileCalled);
	BOOST_REQUIRE_EQUAL("Compute", framework.CompileFromFileLastEntryPoint);
	BOOST_REQUIRE_EQUAL("cs_4_0", framework.CompileFromFileLastProfile);
	BOOST_REQUIRE(device.CreateComputeShaderCalled);
}

APPLICATION_TEST_CASE(OnCreateDeviceShaderNotFound)
{
	framework.FindMediaFakeResult = _T("c:\\tmp\\ComputeShader.hlsl");
	framework.FindMediaFakeThrowHResult = E_UNEXPECTED;
	FakeD3D11Device device;
	BOOST_REQUIRE_EQUAL(E_UNEXPECTED, app->OnCreateDevice(&device, 0));
	BOOST_REQUIRE(framework.FindMediaCalled);
	BOOST_REQUIRE(!framework.CompileFromFileCalled);
	BOOST_REQUIRE(!device.CreateComputeShaderCalled);
}

APPLICATION_TEST_CASE(OnCreateDeviceShaderFailedCompileDisplaysErrorMessage)
{
	framework.FindMediaFakeResult = _T("c:\\tmp\\ComputeShader.hlsl");
	FakeD3D10Blob byteCode;
	framework.CompileFromFileFakeResult = &byteCode;
	framework.CompileFromFileFakeHResult = E_UNEXPECTED;
	FakeD3D10Blob errors;
	std::string errorMessage("Something is wrong in your shader");
	errors.GetBufferPointerFakeResult = const_cast<char *>(errorMessage.c_str());
	errors.GetBufferSizeFakeResult = errorMessage.length();
	framework.CompileFromFileFakeErrors = &errors;
	FakeD3D11Device device;
	BOOST_REQUIRE_EQUAL(E_UNEXPECTED, app->OnCreateDevice(&device, 0));
	BOOST_REQUIRE(framework.FindMediaCalled);
	BOOST_REQUIRE(framework.CompileFromFileCalled);
	BOOST_REQUIRE(!device.CreateComputeShaderCalled);
	BOOST_REQUIRE(framework.DisplayCompileErrorMessageCalled);
	BOOST_REQUIRE(errors.Unknown.ReleaseCalled);
	BOOST_REQUIRE_EQUAL(1, errors.Unknown.ReleaseCalledCount);
}

APPLICATION_TEST_CASE(OnResizedSwapChain)
{
	BOOST_REQUIRE(SUCCEEDED(app->OnResizedSwapChain(0, 0, 0)));
}

APPLICATION_TEST_CASE(OnFrameMove)
{
	app->OnFrameMove(0.0f, 0.0f);
	BOOST_REQUIRE(true);
}

APPLICATION_TEST_CASE(OnFrameRender)
{
	FakeD3D11RenderTargetView rtView;
	framework.GetRenderTargetViewFakeResult = &rtView;
	FakeD3D11DepthStencilView dsView;
	framework.GetDepthStencilViewFakeResult = &dsView;
	FakeD3D11DeviceContext context;
	app->OnFrameRender(0, &context, 0.0f, 0.0f);
	BOOST_REQUIRE(context.ClearRenderTargetViewCalled);
	BOOST_REQUIRE_EQUAL(&rtView, context.ClearRenderTargetViewLastView);
	BOOST_REQUIRE(context.ClearDepthStencilViewCalled);
	BOOST_REQUIRE_EQUAL(&dsView, context.ClearDepthStencilViewLastView);
}

APPLICATION_TEST_CASE(OnReleasingSwapChain)
{
	app->OnReleasingSwapChain();
	BOOST_REQUIRE(true);
}

APPLICATION_TEST_CASE(OnDestroyDevice)
{
	framework.FindMediaFakeResult = _T("c:\\tmp\\ComputeShader.hlsl");
	FakeD3D10Blob byteCode;
	framework.CompileFromFileFakeResult = &byteCode;
	framework.CompileFromFileFakeHResult = S_OK;
	framework.CompileFromFileFakeErrors = 0;
	FakeD3D11Device device;
	FakeD3D11ComputeShader shader;
	device.CreateComputeShaderFakeResult = &shader;
	device.CreateComputeShaderFakeHResult = S_OK;
	app->OnCreateDevice(&device, 0);

	app->OnDestroyDevice();
	BOOST_REQUIRE(shader.Unknown.ReleaseCalled);
	BOOST_REQUIRE_EQUAL(1, shader.Unknown.ReleaseCalledCount);
}

APPLICATION_TEST_CASE(MsgProc)
{
	BOOST_REQUIRE_EQUAL(0, app->MsgProc(0, 0, 0, 0, 0));
}

APPLICATION_TEST_CASE(OnKeyboard)
{
	app->OnKeyboard(0, 0, false);
	BOOST_REQUIRE(true);
}

APPLICATION_TEST_CASE(OnMouse)
{
	app->OnMouse(false, false, false, false, false, 0, 0, 0);
	BOOST_REQUIRE(true);
}

APPLICATION_TEST_CASE(OnDeviceRemoved)
{
	BOOST_REQUIRE(app->OnDeviceRemoved());
}

APPLICATION_TEST_CASE(Startup)
{
	app->Startup();
	BOOST_REQUIRE(true);
}

APPLICATION_TEST_CASE(Shutdown)
{
	app->Shutdown();
	BOOST_REQUIRE(true);
}
